package oop.core.skill;

import oop.core.map.*;
import java.util.*;

/**
 * Cone skill creates a set of temporal locations spreading
 * out from the Avatar's location in either a cone shape or 
 * in a straight line.
 */
public class Cone extends ActiveSkill implements Cloneable{
	private boolean radial;	// true = 90 degrees false = line
	private int dx[] = { 0, -1, 0, 1, -1, 0, 1, -1, 0, 1 };		// Linear mutators
	private int dy[] = { 0, 1, 1, 1, 0, 0, 0, -1, -1, -1 };
	
	/**
	 * Cone constructor.
	 * @param radial
	 * @param name
	 * @param skillLevel
	 * @param lifeTime
	 * @param hitCount
	 * @param effect
	 * @param image
	 * @param delay
	 * @param range
	 * @param passiveSkillsThatAffectMe
	 * @param weaponType
	 */
	public Cone(boolean radial, String name, int skillLevel, long lifeTime, long hitCount, float effect, String image, long delay, int range, List<String> passiveSkillsThatAffectMe, List<String> weaponType){
		super(name, skillLevel, lifeTime, hitCount, effect, image, delay, range, passiveSkillsThatAffectMe, weaponType);
		this.radial = radial;
	}
	
	/**
	 * Helper method that uses the corresponding calculateLocation algorithms
	 * depending on the range of the skill.
	 */
	public List<TemporalLocation> calculateLocationSet(Location loc, int direction){
		List<TemporalLocation> ret = null;
		// for skill done on self
		if(range == 0)
			ret = noRangeCalculateLocationSet(loc);
		// for skill done on surrounding
		else
			ret = rangedCalculateLocationSet(loc,direction);
		return ret;
	}
	
	/**
	 * Calculates the temporal locations for a given location
	 * over a period of time.
	 * @param loc
	 */
	public List<TemporalLocation> noRangeCalculateLocationSet(Location loc){
		List<TemporalLocation> ret = new ArrayList<TemporalLocation>();
		for(int i = 0;i<=lifeTime;i+=(lifeTime/hitCount)){
			ret.add(new TemporalLocation(loc,i));
		}
		return ret;
	}
	
	/**
	 * Calculates the temporal locations for spawning
	 * skillObjects
	 * @param loc
	 * @param direction
	 * @return
	 */
	public List<TemporalLocation> rangedCalculateLocationSet( Location loc, int direction )
	{
		//System.out.println( "DELAY: " + super.propogationDelay );
		
		List<TemporalLocation> ret = new ArrayList<TemporalLocation>();
		
		/*
		 * Handles self-skills
		 */
		if( range == 0 )
		{
			ret.add( new TemporalLocation( loc, 0 ) );
			
			return ret;
		}
		
		/*
		 * Handles cone-trajectories
		 */
		else if( radial )
		{	
			int x = loc.getXPos();
			int y = loc.getYPos();
			boolean cardinal = direction % 2 == 0;
			List<Location> prevRow = new ArrayList<Location>();
			
			switch( direction )
			{
				case 7:
					prevRow.add( new Location( x - 1, y - 1 ) );
					break;
				case 8:
					prevRow.add( new Location( x, y - 1 ) );
					break;
				case 9:
					prevRow.add( new Location( x + 1, y - 1 ) );
					break;
				case 4:
					prevRow.add( new Location( x - 1, y ) );
					break;
				case 6:
					prevRow.add( new Location( x + 1, y ) );
					break;
				case 1:
					prevRow.add( new Location( x - 1, y + 1 ) );
					break;
				case 2:
					prevRow.add( new Location( x, y + 1 ) );
					break;
				case 3:
					prevRow.add( new Location( x + 1, y + 1 ) );
					break;
				default:
					break;
			}
			
			if( range == 1 )
			{
				ret.add( new TemporalLocation( prevRow.get(0), 0 ) );
				return ret;
			}
			
			for( int i = 0; i < range; ++i )
			{
				boolean first = true;
				int fx = 0, fy = 0;
				List<Location> curRow = new ArrayList<Location>();
				
				System.out.println( "row size: " + prevRow.size() );
				
				for( Location l : prevRow )
				{	
					x = l.getXPos();
					y = l.getYPos();
					
					//System.out.println( "(" + x + ", " + y + ")" );

					ret.add( new TemporalLocation( new Location( x, y ), super.propogationDelay * i ) );
					
					if( cardinal )
					{
						switch( direction )
						{
							case 8:
								curRow.add( new Location( x, y - 1 ) );
								break;
								
							case 4:
								curRow.add( new Location( x - 1, y ) );
								break;
								
							case 6:
								curRow.add( new Location( x + 1, y ) );
								break;
								
							case 2:
								curRow.add( new Location( x, y + 1 ) );
								break;
								
							default:
								break;
						}
						
						if( first )
						{
							fx = x;
							fy = y;
							first = false;
						}
					}
					
					else
					{
						if( first )
						{
							switch( direction )
							{
								case 9:
									curRow.add( new Location( x, y - 1 ) );
									break;
									
								case 7:
									curRow.add( new Location( x - 1, y ) );
									break;
								
								case 3:
									curRow.add( new Location( x + 1, y ) );
									break;
								
								case 1:
									curRow.add( new Location( x, y - 1 ) );
									break;
							}
							
							first = false;
						}
						
						switch( direction )
						{
							case 7:
								curRow.add( new Location( x, y - 1 ) );
								break;
								
							case 9:
								curRow.add( new Location( x + 1, y ) );
								break;
							
							case 1:
								curRow.add( new Location( x - 1, y ) );
								break;
							
							case 3:
								curRow.add( new Location( x, y + 1 ) );
								break;
						}
					}
				}
				
				if( cardinal )
				{
					System.out.println( "Direction = " + direction );
					System.out.println( "fx, fy = " + fx + ", " + fy );
					System.out.println( "lx, ly = " + x + ", " + y );
					
					switch( direction )
					{
						case 8:
							curRow.add( 0, new Location( fx + 1, y - 1 ) );
							curRow.add( new Location( x - 1, y - 1 ) );
							break;
							
						case 4:
							curRow.add( 0, new Location( x - 1, fy - 1 ) );
							curRow.add( new Location( x - 1, y + 1 ) );
							break;
							
						case 6:
							curRow.add( 0, new Location( x + 1, fy + 1 ) );
							curRow.add( new Location( x + 1, fy - 1 ) );
							break;
							
						case 2:
							curRow.add( 0, new Location( fx - 1, y + 1 ) );
							curRow.add( new Location( x + 1, y + 1 ) );
							break;
							
						default:
							break;
					}
				}
				
				prevRow = curRow;
			}
		}
		
		/*
		 * Handles linear-trajectories
		 */
		else
		{
			int x = loc.getXPos();
			int y = loc.getYPos();
			for( int i = 0; i < range; ++i )
			{	
				x += dx[ direction ];
				y += dy[ direction ];
				
				ret.add( new TemporalLocation( new Location( x, y ), super.propogationDelay * i ) );
			}
		}
		
		//System.out.println( "Spawn size = " + ret.size() );
		
		for( TemporalLocation tl : ret )
		{
			Location l = tl.getLocation();
			System.out.println( "(" + l.getXPos() +", "+ l.getYPos() + ")" );
		}
		
		return ret;
	}
	
	/**
	 * ~Deprecated Does Not Work~
	 * Calculates the temporal locations for a cone starting
	 * at the given location, in the given direction.
	 * @param loc
	 * @param direction
	 */
//	public List<TemporalLocation> rangedCalculateLocationSet(Location loc, int direction){
//		List<TemporalLocation> ret = new ArrayList<TemporalLocation>();
//		
//		// iterates over a box of all possible locations
//		for(int i = -range;i<=range;i++){
//			for(int j = -range;j<=range;j++){
//				Location newLoc = new Location(i,j);
//				int distance = Location.distance(new Location(0,0), newLoc);
//				long fullPropogationDelay = (distance - 1) * propogationDelay;
//				// for straight line attacks
//				if(!radial){
//					if((direction & 1) == 0){
//						if(direction == 8){
//							if(i==0 && j>0)
//								ret.add(new TemporalLocation(Location.add(loc, newLoc),fullPropogationDelay));
//						}
//						else if(direction == 6){
//							if(j==0 && i>0)
//								ret.add(new TemporalLocation(Location.add(loc, newLoc),fullPropogationDelay));
//						}
//						else if(direction == 4){
//							if(j==0 && i<0)
//								ret.add(new TemporalLocation(Location.add(loc, newLoc),fullPropogationDelay));
//						}
//						else{
//							if(i==0 && j<0)
//								ret.add(new TemporalLocation(Location.add(loc, newLoc),fullPropogationDelay));
//						}
//					}
//					else{
//						if(direction == 9){
//							if(i==j && j>0 && i>0)
//								ret.add(new TemporalLocation(Location.add(loc, newLoc),fullPropogationDelay));
//						}
//						else if(direction == 7){
//							if(i==j && j>0 && i<0)
//								ret.add(new TemporalLocation(Location.add(loc, newLoc),fullPropogationDelay));
//						}
//						else if(direction == 3){
//							if(i==j && j<0 && i>0)
//								ret.add(new TemporalLocation(Location.add(loc, newLoc),fullPropogationDelay));
//						}
//						else{
//							if(i==j && j<0 && i<0)
//								ret.add(new TemporalLocation(Location.add(loc, newLoc),fullPropogationDelay));
//						}
//					}
//				}
//				// for cone attacks
//				else{
//					if((direction & 1) == 0){
//						if(direction == 8){
//							if(j>0 && j>Math.abs(i))
//								ret.add(new TemporalLocation(Location.add(loc, newLoc),fullPropogationDelay));
//						}
//						else if(direction == 6){
//							if(i>0 && i<Math.abs(j))
//								ret.add(new TemporalLocation(Location.add(loc, newLoc),fullPropogationDelay));
//						}
//						else if(direction == 4){
//							if(i<0 && i<Math.abs(j))
//								ret.add(new TemporalLocation(Location.add(loc, newLoc),fullPropogationDelay));
//						}
//						else{
//							if(j<0 && Math.abs(j)>Math.abs(i))
//								ret.add(new TemporalLocation(Location.add(loc, newLoc),fullPropogationDelay));
//						}
//					}
//					else{
//						if(direction == 9){
//							if(j>0 && i>0)
//								ret.add(new TemporalLocation(Location.add(loc, newLoc),fullPropogationDelay));
//						}
//						else if(direction == 7){
//							if(j>0 && i<0)
//								ret.add(new TemporalLocation(Location.add(loc, newLoc),fullPropogationDelay));
//						}
//						else if(direction == 3){
//							if(j<0 && i>0)
//								ret.add(new TemporalLocation(Location.add(loc, newLoc),fullPropogationDelay));
//						}
//						else{
//							if(j<0 && i<0)
//								ret.add(new TemporalLocation(Location.add(loc, newLoc),fullPropogationDelay));
//						}
//					}
//				}
//			}
//		}
//		return ret;
//	}
	public boolean isRadial() {
		return radial;
	}
	public void setRadial(boolean radial) {
		this.radial = radial;
	}	
	
	/**
	 * Implement clone.
	 */
	public Cone clone(){
		Cone cloned = (Cone)super.clone();
		cloned.radial = radial;
		return cloned;
	}
	
	/**
	 * Test method.
	 * @param args
	 */
	public static void main (String[] args){
		Cone cone = new Cone(true, "", 5, 1000,5,5,"",200,5,null,null);
		Location l = new Location(0,0);
		List<TemporalLocation> list = cone.calculateLocationSet(l,2);
		for(TemporalLocation loc : list)
			System.out.println(loc.toString());
	}
}
